let app = getApp()

let cs = app.data.common_store
let op_code = require("./op_code")
let mqtt = require("./mqtt")

import {ble_con_store as bcs} from "../component/ble_con/ble_con_store"
import {random_store} from "../pages/train/random/random_store"

let inArray = (arr, key, val) => {
	for (let i = 0; i < arr.length; i++) {
		if (arr[i][key] === val) {
			return i;
		}
	}
	return -1;
}
// ArrayBuffer转16进制字符串示例
function ab2hex(buffer) {
	var hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function (bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('');
}

// 正确，保留
function ab2str(buf) {
	return String.fromCharCode.apply(null, new Uint8Array(buf));
}
// 正确，保留
function str2ab(str) {
	var buf = new ArrayBuffer(str.length); // 每个字符占用2个字节
	var bufView = new Uint8Array(buf);
	for (var i = 0, strLen = str.length; i < strLen; i++) {
		bufView[i] = str.charCodeAt(i);
	}
	return buf;
}

// 搜索并连接设备
let ble_start = () => {
	get_bt_state().then(() => {
		// console.log("show notice for start")
		let arg = {
			msg: "正在搜索练习器...",
			done_text: "停止",
			done_fn: stop_dev_discovery,
		}
		app.show_n(arg)
		start_dev_discovery()
	})
}

// 获取蓝牙状态，如果可用，则搜索周边设备
// 先初始化蓝牙
let get_bt_state = () => {
	console.log("get_bt_state")
	// 清空蓝牙连接组件的设备列表，以便后续更新
	bcs.dev_info = []
	app.show_notice("正在获取蓝牙状态", "waiting")
	return new Promise((done_fn, fail_fn) => {
		
		open_bt().then(() => {
			console.log("get_bt_state")
			app.resp("获取手机蓝牙状态")
			wx.getBluetoothAdapterState({
				// 获取状态成功
				success: (res) => {
					done_fn(res)
					app.hide_notice()
				},
				// 获取状态失败
				fail: (res) => {
					fail_fn(res)
					app.show_notice("获取蓝牙状态失败")
				}
			})
		}, (resp) => {
			// console.log("fail")
			// fail_fn(resp)
		})
	})
}

// 监听当蓝牙状态发生改变的时候
let on_bt_state_change = () => {
	// console.log("on_bt_state_change")
	wx.onBluetoothAdapterStateChange(function (res) {
		// console.log('onBluetoothAdapterStateChange', res)
		if (res.available) {
			app.resp("蓝牙开启 完成")
			app.set_state("bt", true)
			// 获取当前蓝牙状态，如果可用，则搜索周边设备
			// this.startBluetoothDevicesDiscovery()
			// start_dev_discovery()
		}
		else {
			app.show_notice("蓝牙已关闭，连接练习器需要开启手机蓝牙。")
			app.resp("蓝牙已关闭，请开启蓝牙")
			app.set_state("bt", false)
			app.set_state("cw", false)
		}
	})
}

// 停止搜索附近的蓝牙外围设备
let stop_dev_discovery = () => {
	// console.log("ble -> stop_dev_discovery")
	wx.stopBluetoothDevicesDiscovery({
		success() {
			cs.bt_dev.devs = []
			app.set_state("flag_dev_discovery_start", false)
		}
	})	
}

// 开始搜寻附近的蓝牙外围设备。
// 此操作比较耗费系统资源，请在搜索并连接到设备后调用 wx.stopBluetoothDevicesDiscovery 方法停止搜索。
let start_dev_discovery = () => {
	console.log("开始搜索设备")
	return new Promise((done_fn, fail_fn) => {
		console.log("start_dev_discovery")
		if (app.get_state("flag_dev_discovery_start")) {
			console.log("搜索正在进行，直接返回")
			return
		}
		// app.show_notice("正在尝试搜索练习器...", "waiting")
		app.resp("开始搜索练习器")
		app.set_state("flag_dev_discovery_start", true)
		wx.startBluetoothDevicesDiscovery({
			services: ["6880D7E7-93BA-4FDF-8940-31226AB93AC6"],
			allowDuplicatesKey: true,
			success: (res) => {
				console.log("搜索到设备")
				// console.log('startBluetoothDevicesDiscovery success', res)
				// 监听设备被发现事件
				// this.onBluetoothDeviceFound()
				done_fn(res)
				on_bt_dev_found()
			},
			fail: (res) => {
				fail_fn(res)
			} 
		})
	})
	
}

// 连接设备
let connect_dev = (ds) => {
	return new Promise((done_fn, fail_fn) => {
		console.log("开始连接设备")
		app.resp("开始连接设备")
		app.show_notice("正在连接练习器...", "waiting")
		// // const ds = e.currentTarget.dataset
		const deviceId = ds.deviceId
		const name = ds.name
		wx.createBLEConnection({
			deviceId,
			success: (res) => {
				app.hide_notice()
				app.set_state("cw", true)
				done_fn(res)
				cs.bt_dev.c_dev.name = name
				cs.bt_dev.c_dev.deviceId = deviceId
				cs.bt_dev.c_dev.connected = true
				app.set_state("cw", true)
				done_fn()
				// 获取设备的服务
				get_ble_services(deviceId)
				stop_dev_discovery()
				// this.getBLEDeviceServices(deviceId)
			},	
			fail: (res) => {
				app.show_notice("连接失败，而且不知道为啥失败的")
				app.set_state("cw", false)
				fail_fn(res)
			},
			complete: () => {
			}
		})
		// 停止搜索
		stop_dev_discovery()
		
	})
	
}

// 获取设备服务
let get_ble_services = (deviceId) => {
	
	app.resp("获取练习器的服务信息")
	wx.getBLEDeviceServices({
		deviceId,
		success: (res) => {
			for (let i = 0; i < res.services.length; i++) {
				if (res.services[i].isPrimary) {
					// 获取设备所有特征值
					// this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
					get_ble_c(deviceId, res.services[i].uuid)
					return
				}
			}
		}
	})	
}

// 获取设备所有特征值
let get_ble_c = (deviceId, serviceId) => {
	app.resp("获取服务特征值")
	wx.getBLEDeviceCharacteristics({
		deviceId,
		serviceId,
		success: (res) => {
			// console.log('getBLEDeviceCharacteristics success', res.characteristics)
			for (let i = 0; i < res.characteristics.length; i++) {
				let item = res.characteristics[i]
				if (item.properties.read) {
					// 读取低功耗蓝牙设备的特征值的二进制数值
					wx.readBLECharacteristicValue({
						deviceId,
						serviceId,
						characteristicId: item.uuid,
					})
				}
				if (item.properties.write) {
					cs.bt_dev.c_dev.write = true
					cs.bt_dev.c_dev.deviceId = deviceId
					cs.bt_dev.c_dev.serviceId = serviceId
					cs.bt_dev.c_dev.characteristicId = item.uuid
					// this.writeBLECharacteristicValue()
				}
				if (item.properties.notify || item.properties.indicate) {
					// 启用低功耗蓝牙设备的特征值变化的notify功能
					wx.notifyBLECharacteristicValueChange({
						deviceId,
						serviceId,
						characteristicId: item.uuid,
						state: true,
						success(res) {
							console.log('notifyBLECharacteristicValueChange success', res.errMsg)
						},
						fail(err) {
							console.log('notifyBLECharacteristicValueChange fail', err)
						}
					})
				}
				syn_settings()
			}
			app.resp("准备就绪")
		},
		fail(res) {
			app.resp("获取特征值失败")
			// console.error('getBLEDeviceCharacteristics', res)
		}
	})
	// 操作之前先监听，保证第一时间获取数据
	// 监听低功耗蓝牙设备的特征值变化
	wx.onBLECharacteristicValueChange((characteristic) => {
		// 显示信息，正确的方法
		// this.show_msg(ab2str(characteristic.value))
		// done_fn(ab2str(characteristic.value))


		get_ble_info(characteristic)


		// console.log(ab2str(characteristic.value))
		// // 处理信息
		// // 检查处理方式
		// if(cs.input_code.op_type == "train_random")  {
		// 	random_store.code_op(get_code(ab2str(characteristic.value)))
		// }
		// else if (cs.input_code.op_type == "home"){
		// 	ble_msg_op(ab2str(characteristic.value));
		// }
		// const idx = inArray(cs.bt_dev.chs, 'uuid', characteristic.characteristicId)

		// if (idx === -1) {
		// 	cs.bt_dev.chs[cs.bt_dev.chs.length] = {
		// 		uuid: characteristic.characteristicId,
		// 		value: ab2hex(characteristic.value)
		// 	}
		// } else {
		// 	cs.bt_dev.chs[idx] = {
		// 		uuid: characteristic.characteristicId,
		// 		value: ab2hex(characteristic.value)
		// 	}
		// }

	})
	// 读取低功耗蓝牙设备的特征值的二进制数据值
	wx.readBLECharacteristicValue({
		deviceId,
		serviceId,
		// characteristicId: item.uuid,
		characteristicId: cs.bt_dev.c_dev.characteristicId,
		success(res) {
			app.resp(res)
		}
	})
	// 初始化设备上的设置项目
	
}


// 获取到蓝牙信息
let get_ble_info = (c) => {
	let info = ab2str(c.value)
	if(info == "cmd:play_done") {
		if(app.data.common_store.play_done_callback_fn != "") {
			app.data.common_store.play_done_callback_fn()
		}
		return
	}
	// 处理信息
	// 检查处理方式
	if(cs.input_code.op_type == "train_random")  {
		random_store.code_op(get_code(ab2str(c.value)))
	}
	else if (cs.input_code.op_type == "home"){
		ble_msg_op(ab2str(c.value));
	}
	const idx = inArray(cs.bt_dev.chs, 'uuid', c.characteristicId)

	if (idx === -1) {
		cs.bt_dev.chs[cs.bt_dev.chs.length] = {
			uuid: c.characteristicId,
			value: ab2hex(c.value)
		}
	} else {
		cs.bt_dev.chs[idx] = {
			uuid: c.characteristicId,
			value: ab2hex(c.value)
		}
	}
}


// 开启蓝牙，第一步
let open_bt = () => {
	console.log("ble: open_bt")
	app.show_notice("尝试开启蓝牙", "waiting")
	return new Promise((done_fn, fail_fn) => {
		// console.log("open_bt")
		app.resp("正在初始化手机蓝牙")
		wx.openBluetoothAdapter({
			success: (res) => {
				console.log("开启蓝牙成功")
				app.resp("蓝牙开启 成功")
				app.set_state("bt", true)
				// 开始搜索周边的练习器
				// console.log('openBluetoothAdapter success', res)
				// this.startBluetoothDevicesDiscovery()
				// start_dev_discovery()


				// 当蓝牙设备的连接状态发生改变的时候。
				wx.onBLEConnectionStateChange(function (res) {
					if(!res.connected) {
						cs.bt_dev.c_dev.connected = false
						app.set_state("cw", false)
					}

				})
				on_bt_state_change()
				done_fn(res)
			},
			fail: (res) => {
				console.log("开启蓝牙 失败")
				app.show_notice("尝试使用蓝牙失败，可能是因为手机未开启蓝牙。")
				app.resp("初始化手机蓝牙失败，可能是因为手机未开启蓝牙。")
				fail_fn(res)
				on_bt_state_change()
			},
			complete: () => {
				// 监听蓝牙状态变化
				// on_bt_state_change()
			}
		})
	})

}






// 监听寻找到新设备的事件
let on_bt_dev_found = () => {
	// console.log("on_bt_dev_found")
	app.resp("正在尝试搜索练习器...")
	wx.onBluetoothDeviceFound((res) => {
		app.resp("搜索到练习器...")
		app.hide_notice()
		// 打开连接对话框
		bcs.show_box()
		res.devices.forEach(device => {
			if (!device.name && !device.localName) {
				return
			}
			// const foundDevices = this.data.devices
			device.RSSI = (device.RSSI).toString() + " dBm"
			// 更新连接窗口的信号信息

			const devs = cs.bt_dev.devs
			const idx = inArray(devs, 'deviceId', device.deviceId)
			if (idx === -1) {
				// 如果不在列表中，则增加
				// data[`devices[${foundDevices.length}]`] = device
				// app.data.common_store.bt_dev.devs[app.data.common_store.bt_dev.devs.length] = device
				cs.bt_dev.devs[cs.bt_dev.devs.length] = device
				bcs.dev_info[bcs.dev_info.length] = device
			} else {
				// data[`devices[${idx}]`] = device
				cs.bt_dev.devs[idx] = device
				bcs.dev_info[idx] = device
			}
		})
	})
}

// 断开与设备的连接
let close_dev = () => {
	app.show_notice("正在断开与练习器的连接", "waiting")
	if(cs.bt_dev.c_dev.connected && cs.bt_dev.c_dev.deviceId) {
		wx.closeBLEConnection({
			deviceId: cs.bt_dev.c_dev.deviceId,
			success() {
				// cs.bt_dev.c_dev = {}
				cs.bt_dev.c_dev.connected = false
				app.set_state("cw", false)
				app.show_notice("练习器已断开")
				app.resp("练习器已断开连接")
			}
		})
	}
	else {
		// cs.bt_dev.c_dev = {}
		cs.bt_dev.c_dev.connected = false
		app.set_state("cw", false)
		app.show_notice("练习器已断开")
		app.resp("练习器已断开连接")
	}
	
}

let get_code = (msg) => {
	return { "type": msg.slice(0, 3), "code": msg.slice(4)}
}

let ble_msg_op = (msg) => {
	let msg_type = msg.slice(0, 4)
	let msg_info = msg.slice(4)
	if (msg_type == "inp:") {
		cs.input_code.code += msg_info
		if (msg_info != " ") {
			cs.input_code.temp += msg_info
		} 
		else if (msg_info == " ") {
			if(cs.settings.conv_code) {
				let w = op_code.conv("c2w", cs.input_code.temp)
				cs.input_code.show += w
				cs.input_code.temp = ""
			}
		} 
		cs.input_code.show += msg_info
	}
	else if(msg_type == "cmd:") {
		if(msg_info == "send" && cs.settings.auto_send) {
			mqtt.send_code()
		}
	}
}

// 发送信息
let send = (msg) => {
	// console.log(msg)
	return new Promise((done_fn, fail_fn) => {
		if(cs.bt_dev.c_dev.connected) {
			// 向蓝牙设备发送一个0x00的16进制数据
			let buffer = new ArrayBuffer(1)
			let dataView = new DataView(buffer)
			dataView.setUint8(0, Math.random() * 255 | 0)
			wx.writeBLECharacteristicValue({
				// deviceId: this._deviceId,
				deviceId: cs.bt_dev.c_dev.deviceId,
				// serviceId: this._serviceId,
				serviceId: cs.bt_dev.c_dev.serviceId,
				// characteristicId: this._characteristicId,
				characteristicId: cs.bt_dev.c_dev.characteristicId,
				value: str2ab(msg),
				// value: msg,
				success: (res) => {
					done_fn(res)
				},
				fail: (res) => {
					fail_fn()
				}

			})
		}
		else {
			console.log("bt_dev_not_connected")
			fail_fn()
		}
	})
	
}


// 同步全部设置
let syn_settings = () => {
	// console.log("syn_settings")
	let settings = wx.getStorageSync("settings")
	if (settings != "") {
		cs.settings = settings
	}
	
	if(cs.bt_dev.c_dev.connected) {
		// console.log("send settings items");
		for (let item in cs.settings) {
			send("set:" + item + ":" + cs.settings[item]);
		}
		return true
	}
	else {
		return false
	}
}

let show_box = () => {
	bcs.show_box()
}


module.exports = {
	ble_start: ble_start,
	get_code: get_code,
	show_box: show_box,
	open_bt: open_bt,
	connect_dev: connect_dev,
	start_dev_discovery: start_dev_discovery,
	get_bt_state: get_bt_state,
	stop_dev_discovery: stop_dev_discovery,
	close_dev: close_dev,
	get_ble_c: get_ble_c,
	send: send,
	syn_settings: syn_settings,
}